#ifndef MESH_H
#define MESH_H

class Face;
class Shader;
class Material;
class Triangle;

#include "Troll3D_global.h"
#include "GeoTool/vec4.h"

#include "Material.h"
#include "VertexTemplate.h"

#include "Vertex.h"
#include "Face.h"
#include "Image.h"
#include "Triangle.h"

#include <vector>
#include <string>
#include <QDebug>

/*! @brief Explications :
 *
 *  Un mesh sert tout simplement à enregistrer des sommets et leurs liaisons de manière
 *  à les afficher, suivant les particularités d'une primitive (Triangle, Line etc)
 *
 *  Cependant, la particularité de GLSL est de permettre au programmeur de définir soit même
 *  la nature d'un sommet, décomposé en "attribut".
 *
 *  Beaucoup de moteur graphique définissent "en dur" la structure d'un sommet, en
 *  utilisant les attributs les plus communs, tel que la position, la couleur,
 *  les normales et les coordonnées de texture.
 *
 *  Cependant, pour rendre cette librairie la plus proche possible de la philosophie d'OpenGL,
 *  les sommets sont divisé en "attributs". Un attribut est représenté par un "nom", par le
 *  nombre de GLfloat par sommet (vec4, vec3, vec2), ainsi que l'identifiant GLSL.
 *
 *  Cependant, pour éviter d'invoquer la commande glDraw d'openGL à chaque sommet, une
 *  limitation est à suivre : Un Mesh ne peut contenir des sommets que de la même "structure".
 *  Ainsi, le Mesh m1 devra, avant d'insérer un sommet, préciser la "forme" qu'auront ses sommets.
 *
 *  Pour se faire, il doit invoquer la méthode SetVertexTemplate().
 *
 *  Le Vertex Template, comme son nom l'indique, permet de définir la liste des attributs
 *  autorisé par les sommets du mesh.
 *
 *  vertexTemplate = mesh->SetVertexTemplate();
    vertexTemplate->AddAttribute(4, "position");
    vertexTemplate->AddAttribute(4,"color");
    vertexTemplate->AddAttribute(4,"normal");
    vertexTemplate->AddAttribute(4,"texCoord1");


    Vertex *v1 = mesh->NewVertex();
    v1->SetAttribute("position", -1.0, -1.0, -1.0, 1.0);
    v1->SetAttribute("color", 1.0, 0.0, 0.0, 1.0);
    v1->SetAttribute("normal", 0.0, 0.0, 0.0, 1.0);
    v1->SetAttribute("texCoord1",0.0, 0.0, 0.0, 0.0);
 */
class TROLL3DSHARED_EXPORT Mesh
{
    /************************************************
    /*				Public
    /************************************************/
     public :

        /************************************************
        /*				Constructors
        /************************************************/

            Mesh();

        /************************************************
        /*				Methods
        /************************************************/

            void        Display();
            Vertex &    NewVertex();
            void        NewTriangle(Vertex * v1, Vertex * v2, Vertex * v3);


            void        BindAttribute();

            void        PrintVertices();


            /*! @brief This function will compute the normals of each face inside the Mesh    */
            void ComputeFaceNormals();

            /*! @brief This function will compute the normals of each vertex. Standard workflow is to first compute
             *          the faces normals, and then, for each vertex, we compute the "means" normal of each vertex link
             *          to the current one
             */
            void ComputeVertexNormals();

        /************************************************
        /*				Get/Set
        /************************************************/

            VertexTemplate *    SetVertexTemplate();
            void                SetVertexTemplate(VertexTemplate & vertexTemplate);
            void                SetVertexTemplate(VertexTemplate * vertexTemplate);

            VertexTemplate &    GetVertexTemplate();

            void RemoveVertex(int pos);
            void RemoveTriangle(int pos);


            Material &          material();
            void                material(Material & mat);

        /************************************************
        /*				Properties
        /************************************************/

            VertexTemplate *    m_VertexTemplate;
            Material *          m_Material;
            //float *             datas;
            //GLushort *          indices;


            std::vector<Vertex * >	m_Vertices;
            std::vector<Triangle *> m_Triangles;



        /************************************************
        /*				Private
        /************************************************/
         private :

            /************************************************
            /*				Methods
            /************************************************/

                void UpdateVertices();
                void UpdateTriangles();

                void FlushData();
                void SendDatas();

            /************************************************
            /*				Properties
            /************************************************/

                int offset;


        /************************************************
        /*				Statics
        /************************************************/
        public :
            /************************************************
            /*				Properties
            /************************************************/

            static vector<Vertex*>  s_Vertices;
            static vector<GLuint>   s_Indices;

            static vector<Mesh*>    Meshes;
            static int              TotalAttributes;

            /************************************************
            /*				Methods
            /************************************************/
			
            static void UpdateMeshes();

            /*! @brief : Create a new rectangle. centered on zeo  */
            static  Mesh * NewRect(float width, float height);
			
            static  bool LoadMesh(std::string filePath);

            static float * ReturnVertices();
            static GLuint *ReturnIndices();


};

#endif
